#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
 

typedef struct pd_node {
	char label;
	int all_pu;
	int free_pu;
	int load_pu;
	int p_cnt;
} pd_node_t;

typedef struct vu_node {
	unsigned int pd_bmp;
} vu_node_t;

typedef struct cnd_vu {
	int idx;
	int cft;
} cnd_vu_t;

int vd_w, vu_w, vsu_w, vsu_n;
int pd_cnt, vu_cnt, vsu_cnt;
int check[256][32];
int c_p = 0;
int sel_cnd_vu[32];

#define MAX_PD 256
#define MAX_VU 512
pd_node_t pd_arr[MAX_PD];
vu_node_t vu_arr[MAX_VU];
cnd_vu_t cnd_vu[MAX_VU];

int pd_print_cmp(const void *a, const void *b)
{
	const pd_node_t *ap = (const pd_node_t *)a;
	const pd_node_t *bp = (const pd_node_t *)b;
	
	return ap->label - bp->label;
}

int pd_choose_cmp(const void *a, const void *b)
{
	const pd_node_t *ap = (const pd_node_t *)a;
	const pd_node_t *bp = (const pd_node_t *)b;

	int tmp_a = ap->all_pu * vd_w - ap->load_pu;
	int tmp_b = bp->all_pu * vd_w - bp->load_pu;
	
	if (tmp_a != tmp_b)
		return tmp_b - tmp_a;  /* desc */
	return bp->free_pu - ap->free_pu; /* desc */
}

int char_cmp(const void *a, const void *b)
{
	const char *ap = (const char *)a;
	const char *bp = (const char *)b;

	return *ap - *bp;
}

void print_vu(vu_node_t *vu)
{
	unsigned int bmp = vu->pd_bmp;
	int i = 0;
	
	while (i < sizeof(int) * 8) {
		if (bmp & (1 << i))
			printf("%c ", 'a' + i);	
		i++;
	}
	printf("\n");
}

void print_all_vu(vu_node_t *vu, int n)
{
	int i;
	
	for (i = 0; i < n; i++)
		print_vu(vu + i);
}


int is_conflict(vu_node_t *vu_a, vu_node_t *vu_b)
{
	return (vu_a->pd_bmp & vu_b->pd_bmp) != 0;
}

void cal_vu_cft(int vu_cnt)
{
	int i, j;

	for (i = 0; i < vu_cnt; i++)
		cnd_vu[i].cft = 0;

	for (i = 0; i < vu_cnt; i++) {
		for (j = i + 1; j < vu_cnt; j++) {
			if (!is_conflict(vu_arr + cnd_vu[i].idx, vu_arr + cnd_vu[j].idx))
				continue;
			cnd_vu[i].cft++;
			cnd_vu[j].cft++;
		}
	}
}

int cnd_vu_cmp(const void *a, const void *b)
{
	const cnd_vu_t *ap = (const cnd_vu_t *)a;
	const cnd_vu_t *bp = (const cnd_vu_t *)b;

	return ap->cft - bp->cft;
}

int is_contain(int len, int v)
{
	int i, ret = 0;
	for (i = 0; i < len; i++) {
		if (cnd_vu[sel_cnd_vu[i]].idx == v) {
			ret = 1;
			break;
		}
	}
	return ret;
}

void get_vu()
{
	int i, j; 
	
	printf("########## get these vu for vsu\n");
	for (i = 0; i < vsu_w; i++) {
		print_vu(vu_arr + cnd_vu[sel_cnd_vu[i]].idx);
	}
	for (i = 0, j = 0; i < vu_cnt; i++) {
		memcpy(vu_arr + j, vu_arr + i, sizeof(vu_node_t));
		if (!is_contain(vsu_w, i))
			j++;
	}
	vu_cnt -= vsu_w;
	memset(vu_arr + vu_cnt, 0, sizeof(vu_node_t)*vsu_w);
	printf("########## after get vu, vu info:\n");
	print_all_vu(vu_arr, vu_cnt);
}

int choose_vu(int vu_cnt, int vsu_w, int t, int stop) 
{
	int i, j, ret = -1;

	if (t == vsu_w) {
		for (i = 0; i < vsu_w; i++)
			check[c_p][i] = sel_cnd_vu[i];
		c_p++;
		return 0;
	}

	if (t == 0)
		i = 0;
	else 
		i = sel_cnd_vu[t-1] + 1;

	while(i < vu_cnt) {
		int cft = 0;

		for (j = 0; j < t; j++) {
			if (is_conflict(vu_arr + cnd_vu[sel_cnd_vu[j]].idx, vu_arr + cnd_vu[sel_cnd_vu[i]].idx)) {
				cft = 1;
				break;
			}
		}
		if (t == 0 || cft == 0) {
			sel_cnd_vu[t] = i;
			ret = choose_vu(vu_cnt, vsu_w, t + 1, stop);
			if (ret == 0 && stop == 1)
				break;
		}
		i++;
	}
	return ret;
}

void precise_create_vd(int *e_vu, int e_cnt)
{
	int vu_need = vsu_w - e_cnt;
	int pd_need = vu_need * vu_w;
	int vd_need = (pd_need + vd_w - 2) / (vd_w - 1);
	int pd_max = vd_need * vd_w;
	{
		int sel_pd[pd_max], i, j, k, pd_n; 
		int vd[vd_need][vd_w];
		
		/* to choose pd by capacity */
		qsort(pd_arr, pd_cnt, sizeof(pd_node_t), pd_choose_cmp);
		j = 0;
		for (i = 0; i < pd_cnt; i++) {
			int k, cft_flag = 0;
			unsigned int pd_bmp;

			pd_bmp = 1 << (pd_arr[i].label - 'a');
			for (k = 0; k < e_cnt; k++) {
				if ((pd_bmp & vu_arr[cnd_vu[e_vu[k]].idx].pd_bmp) != 0) {
					cft_flag = 1;
					break;
				}
			}
			if (cft_flag == 0) {
				sel_pd[j++] = i;
			}
		}
		printf("j:%d:pd_need:%d\n", j, pd_need);
		assert(j >= pd_need);
		pd_n = j;

		/* to choose parity pu for every vd */
		for (i = 0; i < vd_need; i++) {
			int min_rej = 100000, index = 0;
			for (j = 0; j < pd_n; j++) {
				if (sel_pd[j] != -1 && pd_arr[sel_pd[j]].rej_cnt < min_rej) {
					index = j;
					min_rej = pd_arr[sel_pd[j]].rej_cnt;
				}
			}
			vd[i][0] = sel_pd[index];
			//printf("index:%d:pd_idx:%d:pd:%c \n", index, sel_pd[index], pd_arr[sel_pd[index]].label);
			sel_pd[index] = -1;
		}

		k = 0;
		for (i = 0; i < vd_need; i++) {
			for (j = 1; j < vd_w; j++) {
				int l, re_flag = 0;

				while(1) {
					re_flag = 0;
					for (l = 0; l < j; l++) {
						if (vd[i][l] == sel_pd[k]) {
							re_flag = 1;
							break;
						}
					}

					if (re_flag == 0 && sel_pd[k] != -1) {
						break;
					} else {
						k++;
						if (k == pd_n)
						k = 0;
					}
				}

				vd[i][j] = sel_pd[k];
				//printf("i:%d:j:%d:k:%d:index:%d:pd:%c\n", i, j, k, sel_pd[k], pd_arr[sel_pd[k]].label);
			}
		}
		
		printf("########## precise create vd \n");
		for (i = 0; i < vd_need; i++) {
			printf("########## vd : %d\n", i);
			for (j = 0; j < vd_w; j++) {
				printf("%c ", pd_arr[vd[i][j]].label);
			}
			printf("\n");
		}
	
		for (i = 0; i < vd_need; i++) {
			for (j = 0; j < vd_w; j++) {
				pd_arr[vd[i][j]].free_pu--;
				pd_arr[vd[i][j]].load_pu++;
			}
			//printf("i:%d:j:%d:vd[i][j]:%d\n", i, 0, vd[i][0]);
			pd_arr[vd[i][0]].load_pu += vd_w - 1;
			pd_arr[vd[i][0]].p_cnt++;

			for (j = 1; j < vd_w; j++) {
				vu_arr[vu_cnt].pd_bmp |= (1 << (pd_arr[vd[i][0]].label - 'a'));
				vu_arr[vu_cnt].pd_bmp |= (1 << (pd_arr[vd[i][j]].label - 'a'));
				if (j % (vu_w - 1) == 0)
					vu_cnt++;
			}
		}
	}
}

/*  return: 1: to stop / other : not to stop */
int check_create(int vu_cnt, int try_w)
{
	int i, j, k, pd_need, pd_avail;

	c_p = 0;
	choose_vu(vu_cnt, try_w, 0, 0);
	if (c_p == 0)
		return -1;
	
	/*	
	{
		int i, j;
		printf("check vu:: try_w:%d\n", try_w);
		for (i = 0; i < c_p; i++) {
			printf("vus:\n");
			for (j = 0; j < try_w; j++) {
				printf("\t");
				print_vu(vu_arr + check[i][j]);
			}
		}
	}
	*/
	
	pd_need = (vsu_w - try_w) * vu_w;
	for (i = 0; i < c_p; i++) {
		pd_avail = 0;
		for (j = 0; j < pd_cnt; j++) {
			int pd_bmp = 1 << (pd_arr[j].label - 'a');
			int cft_flag = 0;
			for (k = 0; k < try_w; k++) {
				if ((pd_bmp & vu_arr[cnd_vu[check[i][k]].idx].pd_bmp) != 0) {
					cft_flag = 1;
					break;
				}
			}
			if (cft_flag == 0 && pd_arr[j].free_pu != 0)
				pd_avail ++;
			if (pd_avail == pd_need) {
				int l;
				printf("possible vus:\n");
				for (l = 0; l < try_w; l++) {
					printf("\t");
					print_vu(vu_arr + cnd_vu[check[i][l]].idx);
				}
				precise_create_vd(check[i], try_w);
				return 0;
			}
		}
	}
	return -1;
}

int precise_add_vd(int vu_cnt)
{
	int i, ret = 1;

	for (i = vsu_w - 1; i > 0; i--) {
		ret = check_create(vu_cnt, i);
		if (ret == 0)
			break;
	}
	return ret;
}

int create_vsu()
{	
	int first, ret = 0, last = 0;
	int vu_no_re;
	
	printf("########## to create a new vsu\n");
	while (1) { /* loop for creat vsu */
		/* TODO:remove duplicate vu */
		vu_no_re = get_no_rep_vu();
		if (vu_no_re < vsu_w)
			goto add_vu;

		cal_vu_cft(vu_no_re);
		qsort(cnd_vu, vu_no_re, sizeof(cnd_vu_t), cnd_vu_cmp);
		
		first = 0;
		/* delete vu can't create a vsu */
		while (first < vu_no_re && vu_no_re - cnd_vu[first].cft < vsu_w)
			first++;
		if (first >= vu_no_re)
			goto add_vu;
		
		ret = choose_vu(vu_no_re, vsu_w, 0, 1);
		if (ret < 0) {
			printf("########## choose vu fail\n");
		} else 
			goto end;
	add_vu:
		if (last) {
			printf("########## Can't create after precise create \n");
			ret = -1;
			goto out;
		}

		printf("########## to create vsu by precise way \n");
		ret = precise_add_vd(vu_no_re);
		if (ret < 0) {
			printf("########## can't create more vsu \n");
			ret = -1;
			goto out;
		}
		last = 1;
	}
end:
	if (ret == 0) {
		get_vu();
	}
out:
	return ret;

}
		
int main(int argc, char **argv)
{
	char c = 'a';
	int i, tmp;

	scanf("%d", &pd_cnt);
	/* init pd info */
	memset(pd_arr, 0, sizeof(pd_node_t) * MAX_PD);
	for (i = 0; i < pd_cnt; i++) {
		scanf("%d", &tmp);
		pd_arr[i].label = c++;
		pd_arr[i].all_pu = tmp;
		pd_arr[i].free_pu = tmp;
	}
	scanf("%d", &vd_w);
	scanf("%d", &vu_w);
	scanf("%d", &vsu_w);
	scanf("%d", &vsu_n);
	if(vsu_n == 0)
		vsu_n = 1024;

	memset(vu_arr, 0, sizeof(vu_node_t) * MAX_VU);

	for (i = 0; i < vsu_n; i++) {
		printf("\n########## create vsu for %d time\n", i);
		tmp = create_vsu();
		if (tmp < 0)
			break;
	}

	printf("########## Finally: vu remains\n");
	print_all_vu(vu_arr, vu_cnt);

	return 0;
}



